// this is the lock server
// the lock client has a similar interface

#ifndef lock_server_h
#define lock_server_h

#include <string>
#include "lock_protocol.h"
#include "lock_client.h"
#include "rpc.h"
#include <mutex>
#include <condition_variable>
#include <unordered_map>
class LocalLockStatus {
 enum class LockStatus{
   FREE=0,
   LOCKED
 };
 public:
  LocalLockStatus(int owner_clt): owner_clt_(owner_clt),status_(LockStatus::FREE){
  }
  void Lock(int clt) {
    std::unique_lock<std::mutex> lk(mutex_lockid);
    while(status_ != LockStatus::FREE) {
        cond_lockid.wait(lk);
    }
    owner_clt_ = clt;
    status_ = LockStatus::LOCKED;
  }
  bool Release(int clt) {
    if (OwnerClientId() != clt) {
      fprintf(stderr, "lock owner is %d, %d cannot release\n", owner_clt_, clt);
      return false;
    }
    {
      std::unique_lock<std::mutex> lk(mutex_lockid);
      owner_clt_ = -1;
      status_ = LockStatus::FREE;
    }
    cond_lockid.notify_all();
    return true;
  }
  int OwnerClientId() {
    return owner_clt_;
  }
 private:
  std::mutex mutex_lockid;
  std::condition_variable cond_lockid;
  int owner_clt_;
  LockStatus status_;
};
class lock_server {

 protected:
  int nacquire;
  std::mutex lock_map_mutex_;
  std::unordered_map<lock_protocol::lockid_t, std::shared_ptr<LocalLockStatus>> lock_map_;


 public:
  lock_server();
  ~lock_server() {};
  lock_protocol::status stat(int clt, lock_protocol::lockid_t lid, int &);
  lock_protocol::status acquire(int clt, lock_protocol::lockid_t lid, int &);
  lock_protocol::status release(int clt, lock_protocol::lockid_t lid, int &);
};

#endif







